﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using T4Common;
using System.Data.SqlClient;
using Microsoft.VisualStudio.TextTemplating;
using T4WinHost.Base;
using System.CodeDom.Compiler;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace T4WinHost
{
	
	public partial class FormSPParameter : Form
	{
		private static object synObj = new object();
		private static DataTable emptyDataTable = new DataTable();
		public StoreProcedure StoreProcedure { get; set; }
		public SqlParameterCollection ParameterCollection { get; set; }
		public string ConnectionStr { get; set; }
		public bool IsCanGenerateFile { get; set; }
		private SqlServerProcMetaReader reader;
		private int taskFinishedCount = 0;
		public FormSPParameter(string connectionStr)
		{
			this.ConnectionStr = connectionStr;
			reader = new SqlServerProcMetaReader(connectionStr);
			InitializeComponent();
		}

		private void FormSPParameter_Load(object sender, EventArgs e)
		{
			DataGridViewTextBoxColumn ColTemplateName = new DataGridViewTextBoxColumn();
			ColTemplateName.DataPropertyName = "CName";
			ColTemplateName.Name = "CName";
			ColTemplateName.HeaderText = "Name";
			ColTemplateName.ReadOnly = true;
			ColTemplateName.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

			DataGridViewCheckBoxColumn ColNullable = new DataGridViewCheckBoxColumn();
			ColNullable.DataPropertyName = "IsNullable";
			ColNullable.HeaderText = "IsNullable";
			ColNullable.Name = "IsNullable";
			ColNullable.Width = 100;
			ColNullable.ReadOnly = true;

			DataGridViewTextBoxColumn ColType = new DataGridViewTextBoxColumn();
			ColType.DataPropertyName = "CType";
			ColType.Name = "CType";
			ColType.HeaderText = "Type";
			ColType.ReadOnly = true;
			ColType.Width = 150;
			gvParameters.AutoGenerateColumns = false;
			gvParameters.Columns.Insert(0, ColTemplateName);
			gvParameters.Columns.Insert(1, ColNullable);
			gvParameters.Columns.Insert(2, ColType);

			gvParameters.DataSource = StoreProcedure.Parameters;
		}

		private void btnExecute_Click(object sender, EventArgs e)
		{
			SqlConnection connection = new SqlConnection(ConnectionStr);
			SqlCommand innerCommand = new SqlCommand() { Connection = connection };
			SqlDataAdapter adapter = new SqlDataAdapter(innerCommand);
			innerCommand.CommandType = CommandType.StoredProcedure;
			innerCommand.CommandText = StoreProcedure.Name;
			var parameters = RetriveCommandParametersFromUI();
			if (parameters != null)
				innerCommand.Parameters.AddRange(parameters);
			else
			{
				innerCommand.Parameters.AddRange(reader.RetriveParametersWithDefaultValue(StoreProcedure.Name));
			}
			DataSet ds = new DataSet();
			try
			{
				adapter.Fill(ds);
				gvResult.DataSource = ds.Tables[0];
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}

		}


		private SqlParameter[] RetriveCommandParametersFromUI()
		{
			bool isAllNull = true;
			List<SqlParameter> parameters = new List<SqlParameter>();
			for (int i = 0; i < gvParameters.RowCount; i++)
			{
				var parameterName = gvParameters.Rows[i].Cells["CName"].Value.ToString();
				var parameterValue = gvParameters.Rows[i].Cells["ColParameterValue"].Value;
				if (parameterValue == null)
					continue;
				isAllNull = false;
				SqlParameter newParameter = new SqlParameter(parameterName, parameterValue);
				parameters.Add(newParameter);
			}
			if (isAllNull)
				return null;
			return parameters.ToArray();
		}

		private void gvParameters_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{
			if (e.ColumnIndex != 0)
				return;
		}

		private void btnGenerate_Click(object sender, EventArgs e)
		{
			btnGenerate.Enabled = false;
			Dictionary<string, List<SpColumn>> storeProcedureResultMeta = null;
			Dictionary<string, List<SpColumn>> storeProcedureParameterMeta = null;
			try
			{
				storeProcedureParameterMeta = reader.RetriveStoreProcedureParameterMeta(new string[] { StoreProcedure.Name });
				Dictionary<string, SqlParameter[]> storeProcedureParameters = null;
				var parameters = RetriveCommandParametersFromUI();
				if (parameters != null)
				{
					if (storeProcedureParameters == null)
						storeProcedureParameters = new Dictionary<string, SqlParameter[]>();
					storeProcedureParameters.Add(StoreProcedure.Name, parameters);
				}
				Dictionary<string, string> failedProcedures = new Dictionary<string, string>();
				storeProcedureResultMeta = reader.RetriveStoreProcedureResultMeta(failedProcedures, new string[] { StoreProcedure.Name }, storeProcedureParameters);

				if (failedProcedures.Count != 0)
				{
					MessageBox.Show(failedProcedures.First().Value);
					btnGenerate.Enabled = true;
					return;
				}

			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				btnGenerate.Enabled = true;
				return;
			}
			T4Parameters.Default.StoreProcedureParametersMeta = storeProcedureParameterMeta;
			T4Parameters.Default.StoreProcedureResultMeta = storeProcedureResultMeta;

			var taskEntity = Task.Factory.StartNew(
					() => GenerateFile(new ThreadStateObject() { TemplateName = "SPEntity.tt" })
				);
			var taskDal = Task.Factory.StartNew(
					() => GenerateFile(new ThreadStateObject() { TemplateName = "SPDal.tt" })
				);
			var taskBiz = Task.Factory.StartNew(
					() => GenerateFile(new ThreadStateObject() { TemplateName = "SPBiz.tt" })
				);

			var taskSyn = Task.Factory.StartNew(
					() => MonitorTask()
				);
		}

		private void MonitorTask()
		{
			while (true)
			{
				if (taskFinishedCount == 3)
				{
					T4Parameters.Default.StoreProcedureParametersMeta = null;
					T4Parameters.Default.StoreProcedureResultMeta = null;
					MethodInvoker methodInvoker = new MethodInvoker(
						()=>btnGenerate.Enabled=true
						);
					Invoke(methodInvoker);
					taskFinishedCount = 0;
					SetLabelText("生成结束",lblGenerate);
					return;
				}
				Thread.Sleep(1000);
			}
		}

		private void GenerateFile(ThreadStateObject threadStateObject)
		{
			try
			{
				SetLabelText(string.Format("正在生成 {0} ", threadStateObject.TemplateName.ToString()),lblGenerate);
				string templateFolder = string.Format(@"{0}\Templates\", Environment.CurrentDirectory);
				TextTemplatingSession session = new TextTemplatingSession();
				session.Add("t4Parameter", T4Parameters.Default);

				CustomCmdLineHost host = new CustomCmdLineHost();
				host.TemplateFileValue = threadStateObject.TemplateName.ToString();
				host.Session = session;
				Engine engine = new Engine();
				//Read the text template.
				string input = File.ReadAllText(templateFolder + threadStateObject.TemplateName);
				input = input.Replace(@"$(ProjectDir)\", "");
				//Transform the text template.
				string output = engine.ProcessTemplate(input, host);
				foreach (CompilerError error in host.Errors)
				{
					Console.WriteLine(error.ToString());
				}
			}
			catch{
				
			}
			lock (synObj)
			{
				taskFinishedCount = taskFinishedCount + 1;
			}
		}

		public void SetLabelText(string text,Label label)
		{
			DelegateSetLabelText method = new DelegateSetLabelText((x,l) => l.Text = x);
			this.Invoke(method, text, label);
		}
	}
}
